<?php

$saveResArr = [];

//这里顺便使用swoole table进行共享内存测试，通常建议使用redis等缓存来保存数据
$table = new Swoole\Table(1024);
$table->column('content', Swoole\Table::TYPE_STRING, 1024);
$table->create();

for ($i = 0; $i < 10000; $i++) {
    $table->set('test', ['content' => 'main start']);                                           //1. 最早执行，输出main start
    Co\run(function () use ($table) {                                                           //2. Co\run执行完之后，才能够走下面的步骤
        $data = $table->get('test')['content'];
        $table->set('test', ['content' => $data . "|coro 1 start"]);                            //2-1. 2中最早执行，输出coro 1 start

        go(function () use ($table) {
            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 2 start"]);                        //2-2. 优先进入协程里面，但是go函数是异步的，并不是必须全部执行完成后才接着往下走，输出coro 2 start
            co::sleep(.001);                                                                    //2-3. 子进程挂起后，执行当前协程的外层代码
            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 2 end"]);                          //2-10 被resume执行，但是sleep 0.001秒后才执行，原则上最先执行
        });


        go(function () use ($table) {
            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 3 start"]);                        //2-4. 优先进入协程里面，输出coro 3 start
            co::sleep(.001);                                                                    //2-5. 子进程挂起后，执行当前协程的外层代码
            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 3 end"]);                          //2-10. 被resume执行，原则上比coro1外层先执行，比coro2慢
        });

        go(function () use ($table) {
            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 4 start"]);                        //2-6. 进入协程，输出coro 4 start

            $data = $table->get('test')['content'];
            $table->set('test', ['content' => $data . "|coro 4 end"]);                          //2-7. 没有被挂起，直接往下执行，输出去coro 4 end
        });


        $data = $table->get('test')['content'];
        $table->set('test', ['content' => $data . "|coro 1 do not wait children coroutine"]);   //2-8. 子进程被挂起，接着执行它,输出coro 1 do not wait children coroutine

        co::sleep(.001);                                                                        //2-9. 挂起，让出当前协程，但是在run中，无法继续执行外面的命令，只能够resume父子所有进程，自己和子进程同时进行
        $data = $table->get('test')['content'];
        $table->set('test', ['content' => $data . "|coro 1 end"]);                              //2-10. 被resume执行，原则上最晚执行

    });

    $data = $table->get('test')['content'];
    $table->set('test', ['content' => $data . "|end"]);                                         //3. run执行完后才可执行

    //保存数据
    $data = $table->get('test')['content'];
    if (!in_array($data, $saveResArr)) {
        $saveResArr[] = $data;
    }

    //释放数据
    $table->del('test');
}


//输出结果
foreach ($saveResArr as $saveRes) {
    foreach (explode('|', $saveRes) as $row) {
        echo $row . PHP_EOL;
    }
    echo '----------------------' . PHP_EOL;
}